﻿#include "NetToolKits.h"

IocpServer::IocpServer(){
	_clientPool = new IocpClientPool();
	_processor = NULL;
}

IocpServer::~IocpServer(){
	_serverAccepting = false;
	_serverReading = false;
	_clientPool->destroyPool();
	delete _clientPool;
}

//normal methods
void IocpServer::onAccept(SOCKET socket){
	IocpClient * client = _clientPool->popUp();
	YHBOOL bconnect = true;
	if (CreateIoCompletionPort(((HANDLE)(socket)), getIocpHandle(), (ULONG_PTR)client, 0) != NULL){
		client->connectSocket = socket;
		memset(&(client->overLapped_recv), 0, sizeof(OVERLAPPED));
		client->operationCode = OP_READ;
		int ret = WSARecv(client->connectSocket, &(client->wsRecvBuff), 1, &(client->dwRecvBytes), &(client->dwFlags), &(client->overLapped_recv), NULL);
		if (ret == SOCKET_ERROR){
			if (WSAGetLastError() != ERROR_IO_PENDING){
				bconnect = false;
				_clientPool->pushBack(client);
			}
		}
		if (bconnect){
			if (_processor != NULL){
				_processor->onAccept(client);
			}
		}
	}
}
void IocpServer::onClose(IocpClient * client){
	if (_processor != NULL){
		_processor->onClose(client);
	}
	_clientPool->pushBack(client);
}
void IocpServer::onRead(IocpClient * client, byte *buffer, int len){
	if (_processor != NULL){
		_processor->onRead(client, buffer, len);
	}
}

YHBOOL IocpServer::isServerAccepting(){
	return _serverAccepting;
}
YHBOOL IocpServer::isServerReading(){
	return _serverReading;
}
HANDLE IocpServer::getIocpHandle(){
	return _hIocp;
}
SOCKET IocpServer::getServerSocket(){
	return _acceptSocket;
}
void IocpServer::setProcessor(IocpServerDelegate* p){
	_processor = p;
}

YHBOOL IocpServer::bindToAddress(string &ipAddr, int port){
	try{
		_acceptSocket = socket(AF_INET, SOCK_STREAM, 0);
		if (_acceptSocket == INVALID_SOCKET){
			int errornum = WSAGetLastError();
			cout <<"socket create error, code is : "<< errornum << endl;
			return false;
		}
		sockaddr_in addr;
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		addr.sin_addr.S_un.S_addr = inet_addr(ipAddr.c_str());
		if (bind(_acceptSocket, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR){
			int errornum = WSAGetLastError();
			cout << "socket bind error, code is : " << errornum << endl;
			return false;
		}
		return true;
	}
	catch (exception &e){

	}
}
YHBOOL IocpServer::startListen(string &ipAddr, int port,int queuelen){
	if (bindToAddress(ipAddr, port)){
		if (listen(_acceptSocket, queuelen) == SOCKET_ERROR){
			int errornum = WSAGetLastError();
			cout << "socket accept error, code is : " << errornum << endl;
			return false;
		}
		if ((_hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0)) == NULL)     //   创建完成端口的句柄  
		{
			int errornum = WSAGetLastError();
			cout << "iocp create error, code is : " << errornum << endl;
			return false;
		}
		//创建连接线程，用来接收客户端的连接  
		this->_serverAccepting = true;  
		_hIocpAcceptThreadHandle = (HANDLE)_beginthreadex(NULL, 0, iocpAcceptThreadProc, (void*)this, 0, &_iIocpAcceptTHreadId);

		//创建工作线程，用来处理完成端口消息的  
		this->_serverReading = true;
		_hIocpWorkThreadHandle = (HANDLE)_beginthreadex(NULL, 0, iocpWorkThreadProc, (void*)this, 0, &_iIocpWorkTHreadId);
		return true;
	}
	else
	{
		return false;
	}
}

//static
uint32 __stdcall IocpServer::iocpWorkThreadProc(LPVOID param){
	static YHBOOL bInit = false;
	IocpServer *pServer = (IocpServer*)param;

	IocpClient* res;
	IocpClient* iocpClient;
	udword recvBytes=0;

	while (pServer->isServerAccepting()){
		int ret;
		ret = GetQueuedCompletionStatus(pServer->getIocpHandle(), &recvBytes, (LPDWORD)&res, (LPOVERLAPPED*)&iocpClient, INFINITE);
		if (ERROR_SUCCESS == ret){
			
		}
		if (recvBytes == 0){
			pServer->onClose(res);
			continue;
		}
		if (res == NULL) return 0;
		switch (iocpClient->operationCode)
		{
		case OP_READ:
			pServer->onRead(res, (byte*)(iocpClient->wsRecvBuff.buf), recvBytes);
			WSARecv(iocpClient->connectSocket, &iocpClient->wsRecvBuff, 1, &(iocpClient->dwRecvBytes), &iocpClient->dwFlags, &iocpClient->overLapped_recv, NULL);
		default:
			break;
		}
	}
	return 0;
}

uint32 __stdcall IocpServer::iocpAcceptThreadProc(LPVOID param){
	IocpServer *pServer = (IocpServer*)param;
	while (pServer->isServerReading()){
		SOCKET client;
		if ((client = accept(pServer->getServerSocket(), NULL, NULL)) == INVALID_SOCKET)
		{
			continue;
		}
		else{
			pServer->onAccept(client);
		} 
	}
	return 1;
}
